package com.wxh.utils;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.security.*;
import java.security.KeyPair;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName: RsaUtils
 * @Description: 非对称加密算法
 * @Author wxh
 * @Date: 2020/7/27 10:12
 * @Version V1.0.0
 * @Since 1.8
 */
public final class RsaUtils {
    /**
     * 使用RSA一般需要产生公钥和私钥，
     * 当采用公钥加密时，使用私钥解密；
     * 当采用私钥加密时，使用公钥解密
     */

    private static Map<Integer, String> keyMap = new HashMap<>();

    private RsaUtils(){
        
    }

    public static void main(String[] args) throws Exception {
        // 生成公钥和私钥
        genKeyPair();

        String message = "df723820";
        System.out.println("未加密的字符串为: " + message);
        System.out.println("随机生成的公钥为: " + keyMap.get(0));
        System.out.println("随机生成的私钥为: " + keyMap.get(1));
        // 加密字符串
        String messageEn = encrypt(message,keyMap.get(0));
        System.out.println(message + " 加密后的字符串为: " + messageEn);
        // 解密字符串
        String messageDe = decrypt(messageEn,keyMap.get(1));
        System.out.println("还原后的字符串为: " + messageDe);
    }

    /**
     * 生成公钥和私钥
     */
    public static void genKeyPair() throws NoSuchAlgorithmException {
        // 秘钥对生成器对象
        KeyPairGenerator keyPairGen =  KeyPairGenerator.getInstance("RSA");
        // 初始化密钥对生成器，密钥大小为96-1024位
        keyPairGen.initialize(1024,new SecureRandom());
        // 生成一个密钥对，保存在keyPair中
        KeyPair keyPair = keyPairGen.generateKeyPair();
        // 得到私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        // 得到公钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        // 编码得到公钥字符串
        String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
        // 编码得到私钥字符串
        String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));
        // 将公钥和私钥保存到Map
        // 0表示公钥
        keyMap.put(0,publicKeyString);
        // 1表示私钥
        keyMap.put(1,privateKeyString);
    }

    /**
     *  根据源字符串和公钥加密改字符串
     * @param sourceStr 需要加密的字符串
     * @param publicKey 公钥
     * @return String
     */
    public static String encrypt(String sourceStr, String publicKey) throws Exception {
        // base64解码的公钥，默认UTF-8
        byte[] decoded = Base64.decodeBase64(publicKey);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        // 公钥的ASN.1编码(规范),编码按照X.509标准
        PublicKey publicKeyObj = keyFactory.generatePublic(new X509EncodedKeySpec(decoded));
        RSAPublicKey pubKey = (RSAPublicKey) publicKeyObj;
        // RSA加密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        byte[] bytes = cipher.doFinal(sourceStr.getBytes("UTF-8"));
        // 编码为base64字符串，目的是为了解密的解码第一步使用
        String outStr = Base64.encodeBase64String(bytes);
        return outStr;
    }

    /**
     *  根据加密后字符串和私钥，解密字符串
     * @param encryptStr 加密后字符串
     * @param privateKey 私钥
     * @return String
     */
    public static String decrypt(String encryptStr, String privateKey) throws Exception {
        // Base64解码加密后的字符串
        byte[] inputByte = Base64.decodeBase64(encryptStr.getBytes("UTF-8"));
        // base64编码的私钥
        byte[] decoded = Base64.decodeBase64(privateKey);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        // 私钥的ASN.1编码(规范),编码按照PKCS#8标准
        PrivateKey privateKeyObj = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(decoded));
        RSAPrivateKey priKey = (RSAPrivateKey) privateKeyObj;
        // RSA解密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, priKey);
        String outStr = new String(cipher.doFinal(inputByte));
        return outStr;
    }
}
